package com.imyuanma.qingyun.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;

/**
 * id生成
 * @author wangjy
 */
public class IDGenerator {
    private static final Logger logger = LoggerFactory.getLogger(IDGenerator.class);
    /**
     * 上一个ID生成时的毫秒数
     */
    private static volatile long lastMillis = 0L;
    /**
     * 当前毫秒生成的id序号
     */
    private static volatile long seq = 0L;

    /**
     * 最大序号
     */
    private static final long MAX_SEQ = 9;

    /**
     * 获取id
     * @return id
     */
    public static long getId() {
        long millis;
        long no;
        synchronized (IDGenerator.class) {
            millis = getMillisForId();
            if (millis > lastMillis) {
                //当前时间戳大于上一次生成时的时间戳, 则重置
                lastMillis = millis;
                seq = 0L;
            }
            no = ++seq;
        }
        StringBuilder sb = new StringBuilder();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millis);

        sb.append(calendar.get(Calendar.YEAR) % 100);
        int m = calendar.get(Calendar.MONTH) + 1;
        if (m < 10) {
            sb.append("0");
        }
        sb.append(m);//月

        int d = calendar.get(Calendar.DAY_OF_MONTH);
        if (d < 10) {
            sb.append("0");
        }
        sb.append(d);//日

        int h = calendar.get(Calendar.HOUR_OF_DAY);
        if (h < 10) {
            sb.append("0");
        }
        sb.append(h);//时

        int min = calendar.get(Calendar.MINUTE);
        if (min < 10) {
            sb.append("0");
        }
        sb.append(min);//分

        int s = calendar.get(Calendar.SECOND);
        if (s < 10) {
            sb.append("0");
        }
        sb.append(s);//秒

        int ms = calendar.get(Calendar.MILLISECOND);
        if (ms < 10) {
            sb.append("00");
        } else if (ms < 100) {
            sb.append("0");
        }
        sb.append(ms);//毫秒

//        if (no < 10) {
//            sb.append("000");
//        } else if (no < 100) {
//            sb.append("00");
//        } else if (no < 1000) {
//            sb.append("0");
//        }
        sb.append(no);//序号

        long id = Long.parseLong(sb.toString());

        logger.info("[ID生成器] 时间戳={},序号={},生成的ID={}", millis, no, id);
        return id;
    }

    /**
     * 获取id生成的时间戳
     * @return
     */
    private static long getMillisForId() {
        long millis = System.currentTimeMillis();
        if (millis < lastMillis) {
            logger.warn("[ID生成器] 发现时光倒流,当前时间戳={},生成器上一次使用的时间戳={}", millis, lastMillis);
            //当前时间小于上一次的生成时间,存在时光倒流,尝试一次获取下一秒时间戳
            //只尝试获取一次,若还是小于上一次,则抛出异常
            millis = getNextMillisForId(millis);
            if (millis < lastMillis) {
                throw new RuntimeException("时钟回退导致无法生成订单号");
            }
        }
        if (millis == lastMillis && seq >= MAX_SEQ) {
            //当前毫秒已经生成过9999次id,则尝试毫秒加1
            millis++;
            logger.info("[ID生成器] 当前毫秒={},目前已经生成{}次id,尝试毫秒数加1", millis, seq);
        }
        return millis;
    }

    /**
     * 获取下一个时间戳
     * @param millis
     * @return
     */
    private static long getNextMillisForId(long millis) {
        long cur = System.currentTimeMillis();
        if (cur - millis > 500L) {
            return cur;
        }
        try {
            logger.info("[ID生成器] 睡眠500ms后重新获取时间戳");
            Thread.sleep(500L);
        } catch (InterruptedException e) {
            logger.error("[ID生成器] 获取下一秒时间戳时线程中断异常", e);
            return cur;
        }
        return getNextMillisForId(millis);
    }

    public static void main(String[] args) {
//        //System.out.println(getId());
//        for (int i=0;i<100;i++) {
//            //long id = getId();
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    //long t1 = System.nanoTime();
//                    long id = getId();
//                    //long t2 = System.nanoTime();
//                    //System.out.println("id="+id+" , 耗时="+(t2-t1)/1000000.0);
//
//                }
//            }).start();
//
//        }
    }

}
